<?php
declare (strict_types=1);

namespace app\service;

use Exception;
use phpseclib3\Math\BigInteger\Engines\PHP;
use Swoole\Server;
use Swoole\Timer;
use think\facade\Cache;
use think\facade\Log;
use think\facade\Queue;

class TcpServerEventHandleService
{
    public $input = null;
    public $output = null;

    public function __construct($input, $output)
    {
        $this->input = $input;
        $this->output = $output;
    }

    public function __get($name)
    {
        try {
            //+----------------------------------------------
            //|注意：类属性成员中未定义才会执行此方法
            //+----------------------------------------------
            if ('redis' == $name) {
                return app(RedisClusterService::class)::run();
            }

            return null;
        } catch (Exception|\RedisClusterException $e) {
            return null;
        }
    }

    public function onStart(Server $server)
    {
        try {
            echo '主进程启动后事件回调' . PHP_EOL;
            //$redis = $this->redisPool->get();
            //Log::record('[REDIS]测试：' . var_export($redis->get('serialAndFdRelation:1227'), true), 'debug');
            //+--------------------------------
            //|Swoole 版本 >= v4.5.0RC1 可用
            //+--------------------------------
            //$masterId = $serv->getMasterPid();
            //$managerId = $serv->getManagerPid();
            //echo "masterPid:{$masterId}" . PHP_EOL;
            //echo "managerId:{$managerId}" . PHP_EOL;
            //file_put_contents(runtime_path() . 'swoole_master.pid', $masterId);
            //file_put_contents(runtime_path() . 'swoole_manager.pid', $managerId);
        } catch (\Exception $e) {
            $this->output->writeln('onStart执行错误:' . $e->getMessage());
        }
    }

    public function onWorkerStart(Server $server, $workerId)
    {
        try {
            echo "workerId:{$workerId}" . PHP_EOL;
            swoole_set_process_name("ice_2025_tcp_server_worker_process:{$workerId}");
        } catch (\Exception $e) {
            $this->output->writeln('onWorkerStart执行错误:' . $e->getMessage());
        }
    }

    public function onConnect(Server $server, $fd): bool
    {
        try {
            $this->output->writeln("链接成功:{$fd}");
            print_r($server->connection_info($fd));
            $command = pack('H*', '01030000000AC5CD');
            $server->send($fd, $command);
            Timer::tick(57000, function ($tid) use ($server, $fd, $command) {
                $this->output->writeln("发送上报数据命令({$fd}):01030000000AC5CD");
                $clientInfo = $server->getClientInfo($fd);
                if (!$clientInfo) return false;
                $this->redis->set("timerId:{$fd}", $tid, 86400 * 7);
                $server->send($fd, $command);
            });
            return true;
        } catch (\Exception $e) {
            $this->output->writeln('onWorkerStart执行错误:' . $e->getMessage());
            return false;
        }
    }

    public function onReceive(Server $server, $fd, $from_id, $data): bool
    {
        try {
            $hexData = bin2hex($data);
            $this->output->writeln("FD:{$fd}; FROM_ID:{$from_id}; data:{$hexData}");

            $data = str_split(substr($hexData, 6), 4);
            foreach ($data as $key => $value) {
                $data[$key] = hexdec($value);
            }

            rabbitmqPush(json_encode([
                'receive_time' => time(),
                'data' => $hexData,
            ], 320));
            $this->output->writeln('数据推入队列');
            return true;
        } catch (Exception $e) {
            $server->close($fd);
            $this->output->writeln('出现异常:' . $e->getMessage() . 'on line:' . $e->getLine());
            Log::record('出现异常:' . $e->getMessage() . ';on line:' . $e->getLine(), 'error');
            return false;
        }
    }

    public function onClose(Server $server, int $fd, int $reactorId)
    {
        try {
            $this->output->writeln('关闭链接:' . $fd . PHP_EOL);
            $serialNo = $this->redis->get("serialAndFdRelation:{$fd}");
            if (!$serialNo) throw new Exception('未授权设备直接关闭连接');
            $this->redis->delete("clientInfo:{$serialNo}");
            $this->redis->delete("serialAndFdRelation:{$fd}");
            $timerId = $this->redis->get("timerId:{$fd}");
            if (!$timerId) throw new Exception('定时器信息错误，直接关闭连接');
            Timer::clear((int)$timerId);
            $this->redis->del("timerId:{$fd}");

            Log::record("设备断开连接：{$serialNo} FD:{$fd}", 'disconnect');
            $server->close($fd);
        } catch (Exception $e) {
            $server->close($fd);
        }
    }
}
